//! 标准输入输出字符设备
//!
//! 对于标准输入的 poll, 目前没有一个完整的对于交互式 io 操作,
//! 例如 mio/tokio 文档中说对标准输入的 poll 会破坏系统行为因此不提供非阻塞的标准输入 poll,
//! 再比如 crossterm 的实现, 提供了非阻塞的 stdin poll, 但是那时最底层的接口, 对外导出的是:
//! `Event` 事件, 而非实际 ascii 码, 除非它后续版本导出原始 buffer, 否则现在无法使用相关接口.
//!
//! 由于 stdio 的实现是主机端的唯一交互接口, 因此实际上也不需要真正的非阻塞,
//! 它一定是需要接收外部事件来终止程序运行的. 所以 stdio 的字符设备实现不是真正的有超时操作,
//! 它一定会一直阻塞, 直到接收到外部事件.
use std::{
    cell::UnsafeCell,
    collections::VecDeque,
    io::{stdin, stdout, Read, Write},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc, LazyLock,
    },
};

use crossterm::terminal::{disable_raw_mode, enable_raw_mode};

use crate::{CharBackendMap, CharDeviceImpl, PollStatus};

/// 标准输入输出字符设备
#[derive(Default)]
pub struct CharDeviceStdio {
    // 可以保证 bufcache 是串行使用的
    bufcache: UnsafeCell<VecDeque<u8>>,
    accept_input: AtomicBool,
}

unsafe impl Send for CharDeviceStdio {}
unsafe impl Sync for CharDeviceStdio {}

impl CharDeviceImpl for CharDeviceStdio {
    fn prepare(&self) -> std::io::Result<()> {
        enable_raw_mode()
    }

    // 没有超时机制可以被实现, 一定会阻塞到数据到来才能返回
    fn poll(&self, _timeout: std::time::Duration) -> std::io::Result<PollStatus> {
        let bufcache = unsafe { &mut (*self.bufcache.get()) };
        if !bufcache.is_empty() && self.accept_input.load(Ordering::Relaxed) {
            self.accept_input.store(false, Ordering::Relaxed);
            return Ok(PollStatus::Ready);
        }

        let mut buf = [0u8; 4096];
        let size = stdin().read(&mut buf)?;
        for s in buf.iter().take(size) {
            bufcache.push_back(*s);
        }
        Ok(PollStatus::Ready)
    }

    fn can_read(&self) -> usize {
        let bufcache = unsafe { &mut (*self.bufcache.get()) };
        bufcache.len()
    }

    fn read(&self, buf: &mut [u8]) -> std::io::Result<usize> {
        let bufcache = unsafe { &mut (*self.bufcache.get()) };
        debug_assert!(!bufcache.is_empty());

        for (idx, this) in buf.iter_mut().enumerate() {
            let ch = bufcache.pop_front();
            if let Some(c) = ch {
                *this = c;
            } else {
                return Ok(idx + 1);
            }
        }
        Ok(buf.len())
    }

    fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
        let sz = stdout().write(buf)?;
        stdout().flush()?;
        Ok(sz)
    }

    fn notify_accept_input(&self) {
        self.accept_input.store(true, Ordering::Relaxed);
    }

    fn end(&self) -> std::io::Result<()> {
        disable_raw_mode()
    }
}

static STDIO_MAP: LazyLock<Arc<CharBackendMap>> =
    LazyLock::new(|| Arc::new(CharBackendMap::default()));

/// 标准输入输出字符后端表
pub fn chardevice_stdio_map() -> Arc<CharBackendMap> {
    STDIO_MAP.clone()
}
